﻿namespace LambdaCalc.Parser.Tests

open System
open NUnit.Framework

open LambdaCalc

[<TestFixture>]
type ``test identifier related evalutation and assignment``() = 

    let translate = Parser.LambdaParser.translate
    let evaluate = Parser.LambdaParser.evaluate

    [<Test>]
    member test.``identifier is replaced by it's assinged expression``() =
        let heap = test.SetpuEnvironment ["X", Core.Atom "y"]
        let input = Parser.Identifier "X"
        let expectedOutput = Core.Atom "y"
        let output = translate heap input
        Assert.AreEqual(expectedOutput, output)

    [<Test>]
    member test.``evaluation of an assignment stores the translated expression in the environment``() =
        let heap = test.SetpuEnvironment []
        let input = Parser.Assignment ("X", Parser.Atom "y")
        let expectedStoredExpression = Core.Atom "y"
        let _ = evaluate heap input
        let storedExpression = heap.LoadExpression("X")
        Assert.AreEqual(expectedStoredExpression, storedExpression)

    [<Test>]
    member test.``evaluation includes a beta-reduction of the result``() =
        let heap = test.SetpuEnvironment []
        let input = Parser.Application [
                        Parser.Abstraction(["x"; "y"], Parser.Application [Parser.Atom "y"; Parser.Atom "x"]);
                        Parser.Atom "a"; Parser.Atom "b" ]
                        |> Parser.Evaluation
        let expectedOutput = Core.Application(Core.Atom "b", Core.Atom "a")
        let parserResult = evaluate heap input
        Assert.AreEqual(expectedOutput, parserResult)

    member test.SetpuEnvironment (keyValuePairs : (Parser.IdentifierName*Core.Expression) list) =
        let map = new System.Collections.Generic.Dictionary<_,_>()
        keyValuePairs |> List.iter (fun (k,e) -> map.Add(k,e))
        { new Parser.IParserEnvironment with
            member i.LoadExpression id = 
                match map.TryGetValue id with
                | false, _         -> failwith (sprintf "Id[%s] not in environment" id)
                | true, expression -> expression
            member i.StoreExpression (id, exp) = map.[id] <- exp
            member i.KnownIdentifiers = map |> Seq.map (fun kvp -> kvp.Key)
            member i.CoreParameters = Core.SystemParameters.Default
        }